﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;

namespace FileWriter
{
    class Program
    {
        static void Main(string[] args)
        {
            //Util util = new Util();
            //Dictionary<string, string> dataMemberList = new Dictionary<string, string>();

            //do
            //{
            //    Console.Write("Enter data name and data type.");
            //    dataMemberList.Add(Console.ReadLine(), Console.ReadLine());

            //}while(Console.ReadLine().Equals(string.Empty));

            int constantID = 0;
            string privateMember = "";
            Console.Write("Enter the name space: ");
            string nameSpace = Console.ReadLine();
            XElement entityFile = XElement.Parse(ORMResources.Entities);
            var rawEntities = entityFile.Descendants("Entity").Select(e => 
                new { 
                    Name = e.Attribute("Name").Value,
                    TableName = e.Attribute("TableName").Value,
                    DataMembers = e });
            foreach (var item in rawEntities)
            {
                string entityName = item.Name;
                string tableName = item.TableName;
                var rawDataMembers = item.DataMembers.Descendants("DataMember").Select(e => 
                    new { 
                          Name = e.Attribute("Name").Value, 
                          DataType = e.Attribute("DataType").Value,
                          ColumnName = e.Attribute("ColumnName").Value,
                          DbType = e.Attribute("DbType").Value
                    });

                StringBuilder privateDataMemberRegion = new StringBuilder();
                privateDataMemberRegion.AppendLine();
                privateDataMemberRegion.AppendLine("\t\t#region Private Data Members");
                privateDataMemberRegion.AppendLine();

                StringBuilder privateStaticDataMemberRegion = new StringBuilder();
                privateStaticDataMemberRegion.AppendLine();
                privateStaticDataMemberRegion.AppendLine("\t\t#region Private \"Static\" Data Members");
                privateStaticDataMemberRegion.AppendLine();
                privateStaticDataMemberRegion.AppendLine("\t\tprivate static readonly string[] _propertyNames = new string[] {");

                StringBuilder constantsRegion = new StringBuilder();
                constantsRegion.AppendLine();
                constantsRegion.AppendLine("\t\t#region Constants");
                constantsRegion.AppendLine();
                constantsRegion.AppendLine("\t\tpublic const int ");

                StringBuilder privateInstanceDataMember = new StringBuilder();
                privateInstanceDataMember.AppendLine();
                privateInstanceDataMember.AppendLine("\t\t#region Private instance data members");
                privateInstanceDataMember.AppendLine();
                privateInstanceDataMember.AppendLine("\t\tprivate FieldInfo[] _fieldInfo = new FieldInfo[]{");

                StringBuilder publicPropertiesRegion = new StringBuilder();
                publicPropertiesRegion.AppendLine();
                publicPropertiesRegion.AppendLine("\t\t#region Public Properties");

                constantID = 0;
                foreach (var v in rawDataMembers)
                {
                    if (!string.IsNullOrEmpty(v.Name) && !string.IsNullOrEmpty(v.DataType))
                    {
                        privateMember = " _" + v.Name.Substring(0, 1).ToLower() + v.Name.Substring(1);

                        privateDataMemberRegion.AppendLine("\t\tprivate " + v.DataType + " " + privateMember + ";");

                        privateStaticDataMemberRegion.AppendLine("\t\t\t\"" + v.Name + "\",");

                        constantsRegion.AppendLine("\t\t\tField" + v.Name + "Idx = " + constantID + ",");

                        privateInstanceDataMember.AppendLine("\t\t\tnew FieldInfo(Field" + v.Name + "Idx,FieldType.Primitive),");

                        publicPropertiesRegion.AppendLine();
                        if (!string.IsNullOrEmpty(v.ColumnName) && !string.IsNullOrEmpty(v.DbType))
                            publicPropertiesRegion.AppendLine("\t\t[Column(DBType = \"" + v.DbType + "\")]");
                        publicPropertiesRegion.AppendLine("\t\tpublic " + v.DataType + " " + v.Name + "");
                        publicPropertiesRegion.AppendLine("\t\t{");
                        publicPropertiesRegion.AppendLine("\t\t\tget { return this.GetHelper(_fieldInfo, _propertyNames, Field" + v.Name + "Idx, " + privateMember + "); }");
                        publicPropertiesRegion.AppendLine("\t\t\tset { " + privateMember + " = this.SetValueTypeHelper(_fieldInfo, Field" + v.Name + 
                            "Idx, " + privateMember + ", value, " + privateMember + " == value); }");
                        publicPropertiesRegion.AppendLine("\t\t}");

                        constantID++;
                    }
                }
                privateDataMemberRegion.AppendLine();
                privateDataMemberRegion.AppendLine("\t\t#endregion");

                privateStaticDataMemberRegion.AppendLine("\t\t};");
                privateStaticDataMemberRegion.AppendLine();
                privateStaticDataMemberRegion.AppendLine("\t\t#endregion");

                constantsRegion.Replace(',', ';', constantsRegion.Length - 3, 2);
                constantsRegion.AppendLine();
                constantsRegion.AppendLine("\t\t#endregion");

                privateInstanceDataMember.AppendLine("\t\t};");
                privateInstanceDataMember.AppendLine();
                privateInstanceDataMember.AppendLine("\t\t#endregion");

                publicPropertiesRegion.AppendLine();
                publicPropertiesRegion.AppendLine("\t\t#endregion");

                StringBuilder sb = new StringBuilder();
                sb.AppendLine("using System;");
                sb.AppendLine("using System.Collections.Generic;");
                sb.AppendLine("using System.Linq;");

                sb.AppendLine();
                sb.AppendLine("namespace " + nameSpace);
                sb.AppendLine("{");
                if (!string.IsNullOrEmpty(tableName))
                    sb.AppendLine("\t[Table(Name = \"" + tableName + "\")]");
                sb.AppendLine("\tpublic class " + entityName);
                sb.AppendLine("\t{");
                sb.Append(privateDataMemberRegion);
                sb.Append(privateStaticDataMemberRegion);
                sb.Append(constantsRegion);
                sb.Append(privateInstanceDataMember);
                sb.Append(publicPropertiesRegion);
                sb.AppendLine("\t}");
                sb.AppendLine("}");


                // create a writer and open the file
                TextWriter tw = new StreamWriter(entityName + ".cs");
                tw.Write(sb);

                tw.Close();
            }


        }
    }
}
